package com.gaff.emp.core.task;

import cn.hutool.core.bean.BeanUtil;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.gaff.emp.core.EmpException;
import com.gaff.emp.core.modules.sys.dao.SysTaskDao;
import com.gaff.emp.core.modules.sys.entity.SysTask;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationListener;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
import org.springframework.scheduling.support.CronTrigger;
import org.springframework.stereotype.Component;

import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ScheduledFuture;

@Slf4j
@Component
public class DynamicTask implements ApplicationListener<ContextRefreshedEvent> {

    @Autowired
    private SysTaskDao sysTaskDao;

    @Autowired
    private ThreadPoolTaskScheduler threadPoolTaskScheduler;

    private Map<String, ScheduledFuture<?>> futureMap = new ConcurrentHashMap<>();

    public void addTask(SysTask sysTask) throws Exception {
        Objects.requireNonNull(sysTask.getTaskName());
        Objects.requireNonNull(sysTask.getClassName());
        Objects.requireNonNull(sysTask.getCron());
        SysTask task = sysTaskDao.selectOne(Wrappers.<SysTask>query().eq("task_name", sysTask.getTaskName()));
        if (task != null) {
            throw new EmpException("任务名称重复");
        }
        sysTaskDao.insert(sysTask);
        executeTask(sysTask);
    }

    public void removeTask(String taskName) {
        SysTask task = sysTaskDao.selectOne(Wrappers.<SysTask>query().eq("task_name", taskName));
        if (task == null) {
            return;
        }
        sysTaskDao.deleteById(task.getId());
        ScheduledFuture<?> future = futureMap.remove(task.getTaskName());
        if (future != null) {
            future.cancel(true);
        }
    }

    public void updateTask(SysTask sysTask) throws Exception {
        Objects.requireNonNull(sysTask.getTaskName());
        Objects.requireNonNull(sysTask.getClassName());
        Objects.requireNonNull(sysTask.getCron());
        SysTask task = sysTaskDao.selectOne(Wrappers.<SysTask>query().eq("task_name", sysTask.getTaskName()));
        if (task == null) {
            throw new EmpException("任务不存在");
        }
        BeanUtil.copyProperties(sysTask, task);
        sysTaskDao.updateById(task);
        ScheduledFuture<?> future = futureMap.remove(task.getTaskName());
        if (future != null) {
            future.cancel(true);
        }
        executeTask(task);
    }

    @Override
    public void onApplicationEvent(ContextRefreshedEvent event) {
        if (event.getApplicationContext().getParent() == null) {
            List<SysTask> tasks = sysTaskDao.selectList(Wrappers.emptyWrapper());
            for (SysTask task : tasks) {
                executeTask(task);
            }
        }
    }

    private void executeTask(SysTask task) {
        try {
            Class clazz = Class.forName(task.getClassName());
            if (!EmpTask.class.isAssignableFrom(clazz)) {
                log.warn("executeTask failed, Class [" + task.getClassName() + " is not extend EmpTask.class");
                return;
            }
            EmpTask empTask = (EmpTask) clazz.newInstance();
            empTask.setParams(task.getParams());
            ScheduledFuture<?> future = threadPoolTaskScheduler.schedule(empTask, new CronTrigger(task.getCron()));
            futureMap.put(task.getTaskName(), future);
        } catch (Exception e) {
            log.error("executeTask error", e);
        }
    }

}
